package cate.game;

import cate.game.serve.ServeManager;
import cate.game.trace.TraceManager;
import cate.game.world.invite.InviteManager;
import cp.bi.CpBiClient;
import cp.game.framework.ILogcat;
import cp.solution.util.time.DateKit;
import cate.game.activity.base.ActivityGlobalManager;
import cate.game.common.rpc.RpcListener4Game;
import cate.game.common.rpc.RpcSender4Game;
import cate.game.common.time.TimeManager;
import cate.game.cross.CrossManager;
import cate.game.demo.DemoManager;
import cate.game.friend.aid.FriendAidManager;
import cate.game.gm.GmManager;
import cate.game.interact.InteractManager;
import cate.game.log.GameLoggerFactory;
import cate.game.admin.AdminManager;
import cate.game.attr.PowerManager;
import cate.game.chat.ChatManager;
import cate.game.client.ClientManager;
import cate.game.client.interceptor.CommandExecutor;
import cate.game.db.DbFacadeManager;
import cate.game.event.GameEventDispatcher;
import cate.game.farm.FarmManager;
import cate.game.fight.FightManager;
import cate.game.framework.GameConfig;
import cate.game.framework.GameFacilities;
import cate.game.framework.ModuleManager;
import cate.game.friend.FriendManager;
import cate.game.mail.MailManager;
import cate.game.notice.NoticeManager;
import cate.game.pay.PayManager;
import cate.game.play.PlayManager;
import cate.game.pvp.PvpManager;
import cate.game.rank.RankManager;
import cate.game.rank.cross.CrossRankManager;
import cate.game.res.ResManager;
import cate.game.role.RoleManager;
import cate.game.role.farm.cache.FightCacheManager;
import cate.game.stat.StatManager;
import cate.game.status.GameStatusManager;
import cate.game.status.SpanExe;
import cate.game.table.TableManager;
import cate.game.train.TrainManager;
import cate.game.util.GameTools;
import cate.game.util.IntervalCounter;
import cate.game.videohall.VideoHallManager;
import cate.game.world.WorldManager;
import cp.solution.manage.PrimaryClient;
import cp.solution.manage.api.open.OpenApi;
import cp.solution.manage.cache.PrimaryLoader;
import cp.solution.ops.status.SysOprStatus;
import cp.solution.util.collection.ListKit;
import easy.java.dev.note.NoteField;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Slf4j
public class GameBody {

    public static String version() {
        return "GameBody 2023-10-27 16:38";
    }

    public ManyGame process;
    /**
     * 是否正在关闭
     */
    private volatile boolean shutdownIng;
    /**
     * 是否已关闭
     */
    public volatile boolean shutdownDone;

    /** 忽略客户端消息 */
    public volatile boolean clientIgn = false;

    @NoteField("未开的服延迟加载")
    public boolean lazyInit;
    public GameConfig config;

    public GameFacilities facilities;
    public GameEventDispatcher eventDispatcher;
    public CommandExecutor commandExecutor;
    public SpanExe span;

    public RpcListener4Game rpcRecv() {
        return facilities.getRpcListener();
    }

    public RpcSender4Game rpcSend() {
        return facilities.getRpcSender();
    }

    public PrimaryClient apis() {
        return facilities.getApi().pc();
    }

    public PrimaryLoader apisLoader() {
        return facilities.getApi().pl();
    }

    public OpenApi openApi() {
        return facilities.getApi().open();
    }

    public CpBiClient bi() {
        return facilities.getBi();
    }

    /**
     * @param autoNewModule 是否自动new模块
     */
    public GameBody(boolean autoNewModule) {
        if (autoNewModule) {
            span = new SpanExe(this);
            time = new TimeManager();
            status = new GameStatusManager();
            role = new RoleManager();
            notice = new NoticeManager();
            friend = new FriendManager();
            friendAid = new FriendAidManager();
            mail = new MailManager();
            play = new PlayManager();
            fight = new FightManager();
            train = new TrainManager();
            farm = new FarmManager();
            rank = new RankManager();
            crossRank = new CrossRankManager();
            chat = new ChatManager();
            world = new WorldManager();
            client = new ClientManager();
            stat = new StatManager();
            trace = new TraceManager();
            admin = new AdminManager();
            db = new DbFacadeManager();
            power = new PowerManager();
            res = new ResManager();
            pvp = new PvpManager();
            videoHall = new VideoHallManager();
            activityGlobal = new ActivityGlobalManager();
            demo = new DemoManager();
            cross = new CrossManager();
            pay = new PayManager();
            fightCache = new FightCacheManager();
            gm = new GmManager();
            serve = new ServeManager();
            interact = new InteractManager();
            invite = new InviteManager();
        }
    }

    /**
     * 配置表模块
     */
    public TableManager table;
    /**
     * 工具包
     */
    public GameTools tools;
    /**
     * 时间管理
     */
    public TimeManager time;
    /**
     * 游戏状态数据
     */
    public GameStatusManager status;
    /**
     * 角色模块
     */
    public RoleManager role;
    /**
     * 通知模块
     */
    public NoticeManager notice;
    /**
     * 好友模块
     */
    public FriendManager friend;

    public FriendAidManager friendAid;
    /**
     * 邮件模块
     */
    public MailManager mail;
    /**
     * 剧本模块
     */
    public PlayManager play;
    /**
     * 战斗模块
     */
    public FightManager fight;
    /**
     * 养成模块
     */
    public TrainManager train;
    /**
     * farm玩法模块
     */
    public FarmManager farm;
    /**
     * 排行榜模块
     */
    public RankManager rank;
    public CrossRankManager crossRank;
    /**
     * 聊天模块
     */
    public ChatManager chat;
    /**
     * 世界服业务模块
     */
    public WorldManager world;
    /**
     * 客户端管理模块
     */
    public ClientManager client;
    /**
     * 统计模块
     */
    public StatManager stat;
    /** 数据打点模块 */
    public TraceManager trace;
    /**
     * gm工具模块
     */
    public AdminManager admin;
    /**
     * 数据库模块
     */
    public DbFacadeManager db;
    /**
     * 战力模块
     */
    public PowerManager power;
    /**
     * 资源玩法
     */
    public ResManager res;
    /**
     * pvp功能模块
     */
    public PvpManager pvp;
    /**
     * 录像馆
     */
    public VideoHallManager videoHall;
    /**
     * 活动模块
     */
    public ActivityGlobalManager activityGlobal;
    /**
     * demo模块
     */
    public DemoManager demo;

    /**
     * 跨服管理
     */
    public CrossManager cross;


    public PayManager pay;
    /**
     * 战斗缓存
     */
    public FightCacheManager fightCache;

    public GmManager gm;
    public ServeManager serve;

    /** 玩家之间互动管理 */
    public InteractManager interact;
    public InviteManager invite;

    /**
     * 初始化游戏各个模块
     */
    public void init(boolean lazyInit) throws Exception {
        Objects.requireNonNull(this.facilities);
        this.lazyInit = lazyInit;
        if (lazyInit) {
            return;
        }
        gameInit();
    }

    public void starLazyInit() throws Exception {
        if (!lazyInit) {
            return;
        }
        if (facilities == null) {
            throw new Exception("facilities怎么没了呢??");
        }
        gameInit();
    }

    private void gameInit() throws Exception {
        final long allBeginTime = System.currentTimeMillis();
        ModuleManager[] ms = new ModuleManager[]{
                db, time, status, role, notice, friend, friendAid, mail, play, fight, train, farm, rank, crossRank, chat, world, client,
                stat, trace, admin, power, res, pvp, videoHall, demo, cross, activityGlobal, pay, fightCache, gm, serve, interact, invite
        };
        List<String> highCostLogs = new ArrayList<>();
        for (ModuleManager m : ms) {
            long beginTime = System.currentTimeMillis();
            //log.info("模块{} initIndependent 开始", m.getClass());
            m.initIndependent(this);
            long costTime = System.currentTimeMillis() - beginTime;
            if (costTime > 100L) {
                highCostLogs.add("模块" + m.getClass().getName() + " initIndependent 耗时" + costTime + "ms");
            }
        }
        for (ModuleManager m : ms) {
            try {
                long beginTime = System.currentTimeMillis();
                //log.info("模块{} initDependent 开始", m.getClass());
                m.initDependent();
                long costTime = System.currentTimeMillis() - beginTime;
                if (costTime > 100L) {
                    highCostLogs.add("模块" + m.getClass().getName() + " initDependent 耗时" + costTime + "ms");
                }
            } catch (Exception e) {
                GameLoggerFactory.getLogger(this, GameBody.class).error("", e);
            }
        }
        if (!highCostLogs.isEmpty()) {
            log.warn("模块初始化超时日志 (srvId={}) \r\n{}", this.config.srvId, ListKit.print(highCostLogs, "\r\n"));
        }
        span.checkSpan();
        facilities.afterGameInitialize();
        log.info("GameBody(srvId={})各游戏业务逻辑模块总共初始化耗时 {}ms", this.config.srvId, (System.currentTimeMillis() - allBeginTime));
    }

    /**
     * 游戏服重启
     */
    public void restart() throws Exception {
        this.shutdownIng = false;
        this.shutdownDone = false;
        this.clientIgn = false;
        this.init(false);
    }

    public boolean isRunning() {
        if (this.shutdownIng) {
            return false;
        }
        if (this.shutdownDone) {
            return false;
        }
        return !this.lazyInit;
    }

    public void shutdown() {
        if (this.shutdownIng) {
            return;
        }
        if (!isRunning()) {
            this.shutdownDone = true;
            return;
        }
        this.shutdownIng = true;
        log.info("shutdown开始 {}:{}", this.config.srvId, this.config.gs.getName());
        this.client.shutdown();
        this.fight.shutdown();
        this.status.shutdown();
        this.mail.shutdown();
        this.pvp.shutdown();
        this.rank.shutdown();
        this.crossRank.shutdown();
        this.farm.shutdown();
        this.res.shutdown();
        this.activityGlobal.shutdown();
        this.videoHall.save();
        this.role.saveAll();
        this.stat.shutdownSafe();
        this.trace.shutdownSafe();
        this.friend.shutdownSafe();
        this.friendAid.shutdownSafe();
        this.demo.shutdownSafe();
        this.pay.shutdownSafe();
        this.shutdownDone = true;
    }

    public void onDaySpan() {
        if (!isRunning()) {
            return;
        }
        this.status.onDaySpanSafe();
        this.res.onDaySpanSafe();
        this.mail.onDaySpanSafe();
        this.pvp.onDaySpanSafe();
        this.friendAid.onDaySpanSafe();
        this.rank.onDaySpanSafe();
        this.fight.onDaySpanSafe();
        this.farm.onDaySpanSafe();
        this.activityGlobal.onDaySpanSafe();
        this.role.onDaySpanSafe();
    }

    public void onWeekSpan() {
        if (!isRunning()) {
            return;
        }
        this.status.onWeekSpanSafe();
        this.res.onWeekSpanSafe();
        this.mail.onWeekSpanSafe();
        this.pvp.onWeekSpanSafe();
        this.rank.onWeekSpanSafe();
        this.fight.onWeekSpanSafe();
        this.farm.onWeekSpanSafe();
        this.activityGlobal.onWeekSpanSafe();
        this.role.onWeekSpanSafe();
    }

    public void onMonthSpan() {
        if (!isRunning()) {
            return;
        }
        this.status.onMonthSpanSafe();
        this.res.onMonthSpanSafe();
        this.mail.onMonthSpanSafe();
        this.pvp.onMonthSpanSafe();
        this.rank.onMonthSpanSafe();
        this.fight.onMonthSpanSafe();
        this.farm.onMonthSpanSafe();
        this.videoHall.onMonthSpanSafe();
        this.activityGlobal.onMonthSpanSafe();
        this.role.onMonthSpanSafe();
    }

    public void onHourSpan() {
        role.activeForOnline(role -> role.getTrace().recordOnlineTraceDaily());
    }

    private final IntervalCounter roleTrigger = new IntervalCounter(3);

    public void tick() {
        if (!isRunning()) {
            return;
        }
        fight.task.checkTask();
        res.guild.getGuildList()
                .forEach(guild -> guild.tick());
        if (roleTrigger.trigger()) {
            role.activeForOnline(role ->
                    {
                        role.getBag().tick();
                        role.getShow().tick();
                        role.getActivity().tick();
                        role.getFarm().tick();
                        role.getRes().tick();
                        role.getFriend().tick();
                        role.getPvp().tick();
                        role.getPay().tick();
                    }
            );
        }
        activityGlobal.tick();
        farm.local.tick();
        pvp.tick();
        stat.tick();
        trace.tick();
        cross.tick();
        world.tick();
        status.tick();
        res.tick();
        mail.tick();
        rank.tick();
        friend.tick();
        demo.tick();
        bi().tick();
    }

    /**
     * 每3分钟
     */
    public void every3Min() {
        if (!isRunning()) {
            return;
        }
        this.stat.every3Min();
    }

    public long getOpenTime() {
        return config.getOpenTime() > 0 ? config.getOpenTime() : status.getOpenTime();
    }

    public int getOpenDay() {
        // 开服时间如果在未来 那就算第0天
        if (this.getOpenTime() > System.currentTimeMillis()) {
            return 0;
        }
        return DateKit.getDistanceDays(this.getOpenTime(), System.currentTimeMillis()) + 1;
    }

    public long getMergeTime() {
        //合服时间暂时没配置
        return config.getMergeTime();
    }

    public ILogcat logcat() {
        return process.logcat;
    }

    private final SysOprStatus sos = new SysOprStatus();

    public SysOprStatus loadSysOprStatus() {
        return this.sos;
    }

    /**
     * 处理被合服吞并前的结算
     */
    public SysOprStatus handleMergeSettle() {
        this.clientIgn = true;
        sos.checkRunnableAndStart("合服结算");
        sos.setGs(this.config.gs);
        ModuleManager[] ms = new ModuleManager[]{
                status, role, friend, friendAid, mail, play, fight, train, farm, rank, crossRank, chat, world,
                res, pvp, videoHall, demo, cross, activityGlobal
        };
        try {
            for (ModuleManager m : ms) {
                sos.addMod(m.handleMergeSettle());
            }
        } catch (Exception e) {
            log.error("处理被合服吞并前的结算 发生了异常 ", e);
            sos.setErrMsg(e.getMessage());
        }
        sos.modsDone();
        //new Thread(() -> role.traversal.doMergeSettle(sos), "merge-settle-roles").start();
        sos.setRunning(false);
        return sos;
    }

    /**
     * 处理游戏服数据清理
     */
    public SysOprStatus handleCleanData() {
        sos.checkRunnableAndStart("数据清理");
        sos.setGs(this.config.gs);

        new Thread(() -> {
            role.traversal.doCleanData(sos);

            ModuleManager[] ms = new ModuleManager[]{
                    status, role, friend, friendAid, mail, play, fight, train, farm, rank, crossRank, chat, world,
                    res, pvp, videoHall, demo, cross, activityGlobal
            };
            try {
                for (ModuleManager m : ms) {
                    sos.addMod(m.handleCleanData());
                }
            } catch (Exception e) {
                log.error("处理数据清理 发生了异常 ", e);
                sos.setErrMsg(e.getMessage());
            }
            sos.modsDone();

        }, "clean-data-roles").start();
        return sos;
    }

    @Override
    public String toString() {
        if (this.config != null && this.config.gs != null) {
            return this.config.gs.getName() + "(" + this.config.gs.getId() + ")";
        } else {
            return "GameBody";
        }
    }
}
